class myVue {
  constructor(options){
    //保存数据
    this.$options = options
    this.$data = options.data
    this.$el = options.el  

    //将数据添加到响应式系统
    new Observer(this.$data)

    //代理this.$data
    Object.keys(this.$data).forEach(key=>{
      this._proxy(key)
    })

    //处理el
    new Compiler(this.$el,this)
  }

  //this代理
  _proxy(key){
      Object.defineProperty(this,key,{
        configurable:true,
        enumerable:true,
        set(newValue){
          this.$data[key] = newValue
        },
        get(){
          return this.$data[key]
        }
      })  
  }
}

//监听data数据的变化
class Observer{
  constructor(data){
    this.data = data;
    Object.keys(data).forEach(key=>{
      this.defineReactive(this.data, key, data[key])
    })
  }

  //把data数据用defineproperty创建一个新对象，get，set监听变化
  defineReactive(data,key,val){
    const dep = new Dep()
    Object.defineProperty(data,key,{
      configurable:true,
      enumerable:true,
      get(){
        //Dep.target = watcher
        //在Dep中添加订阅类
        if(Dep.target){
          dep.addSub(Dep.target)
        }
        return val
      },
      set(newValue){
        if(newValue == val){
          return
        }
        val = newValue
        //数据被更改，通知dep更新数据
        dep.notify()
      }
    })
  }
}

//发布者响应类
class Dep {
  constructor(){
    //记录所有的订阅类
    this.subs = []
  }
  //添加订阅类
  addSub(sub){
    this.subs.push(sub)
  }
  //发布通知
  notify(){
    this.subs.forEach(sub=>{
      sub.update()
    })
  }
}

//观察者订阅类
class Watcher {
  constructor(node , name , vm){
    this.node = node
    this.name = name
    this.vm = vm
    Dep.target = this
    this.update()
    Dep.target = null
  }

  //更新视图
  update(){
    this.node.nodeValue = this.vm[this.name]
  }
}

//对{{}}判断的正则
const reg = /\{\{(.+)\}\}/

class Compiler {
  constructor(el,vm){
    this.el = document.querySelector(el)    
    this.vm = vm 

    this.frag = this._createFragment(this.el)
    this.el.appendChild(this.frag)
  }

  _createFragment(el){
    const frag = document.createDocumentFragment()
    //每次循环会把el的节点清除，放在新的文档frag中append回el节点
    let child;
    while(child = el.firstChild){
      this._compiler(child)
      frag.appendChild(child)
    }
    return frag
  }

  _compiler(node){
    if(node.nodeType == 1){  //标签节点
      const attrs = node.attributes
      //input标签的双向绑定
      if(attrs.hasOwnProperty('v-model')){
        const name = attrs['v-model'].nodeValue
        node.addEventListener("input",e=>{
          this.vm[name] = e.target.value
        })
      }
      //递归查找子节点的文本
      let frags = this._createFragment(node)
      node.appendChild(frags)
    }
    if(node.nodeType == 3){  //文本节点
        if(reg.test(node.nodeValue)){
          //refexp.$1 获取匹配到的第一个（）
          const name = RegExp.$1.trim()
          //订阅数据变化，绑定更新函数
          new Watcher(node, name ,this.vm)
        }
    }
  }

}